#include "SH_Chain.h"
#include "SH_Cell.h"

SH_Chain::SH_Chain(int _direction) {
	direction = _direction;
	cell = 0;
	resource = 0;
	state = ~0;
	value = 0;
	freqState = 0;
	second = false;
}

SH_Chain::~SH_Chain() {
}

void SH_Chain::setCell(SH_Cell *c) {
	cell = c;
}

void SH_Chain::run(SH_Purpose p, SH_Cell *startCell) {
	
	purpose = p;
	resource = 9;
	value = 0;
	freqState = 0;
	second = false;
	
	// В зависимости от purpose state имеет различную семантику
	if (p == SH_PurposeInit) state = ~0;
	else state = 0;
	
	if (startCell) cell = startCell;
	
	while (1) if(!step()) break;
	
}

bool SH_Chain::step() {

	// Какой-то баг компилятора, но почему-то лучше не объявлять переменные внутри case'ов
	int stateCount, num, i;

	if (!resource) return false;
	resource--;
		
	switch (purpose) {
		
		case SH_PurposeInit:
			
			num = cell->get();
			
			if (num && state & (0x1 << num)) {

				state &= ~(0x1 << num);
				resource = 9;
				
			} else cell->appendState(state); 
			
		break; case SH_PurposeSearch:
			
			
			// Алгоритм 1. Единственный вариант в ячейке
			
			for (i = 1, stateCount = 0; i <= 9; i++) {
				if (cell->getState() & (0x1 << i)) stateCount++; 
			}
			
			if (stateCount == 1) {
				
				// Поиск позиции бита (он гарантированно один)
				for (i = 1; i <= 9; i++) {
					if (cell->getState() & (0x1 << i)) break; 
				}
				
				if (i > 9) break;

				cell->set(i);
				
				cell->getChain(0)->run(SH_PurposeAction, cell);
				cell->getChain(1)->run(SH_PurposeAction, cell);
				cell->getChain(2)->run(SH_PurposeAction, cell);
				
				cell->getChain(0)->run(SH_PurposeSearch, cell);
				cell->getChain(1)->run(SH_PurposeSearch, cell);
				cell->getChain(2)->run(SH_PurposeSearch, cell);
				
				return false;
				
			}
			
			// Алгоритм 2. Единственный вариант в цепочке
			
			if (!second) {	// Сначала вычисляем state и freqState
				freqState |= state & cell->getState();
				state |= cell->getState();
				
				// Переходим во вторую стадию
				if (!resource) {
					resource = 9;
					second = true;
				}
				
			} else { // Вторая стадия: установка значения
				
				SH_State resultState = state & ~freqState & cell->getState();
	
				// Поиск позиции бита (он один)
				for (i = 1; i <= 9; i++) {
					if (resultState & (0x1 << i)) break; 
				}
				
				if (i > 9) break;
				
				cell->set(i);
	
				cell->getChain(0)->run(SH_PurposeAction, cell);
				cell->getChain(1)->run(SH_PurposeAction, cell);
				cell->getChain(2)->run(SH_PurposeAction, cell);
				
				cell->getChain(0)->run(SH_PurposeSearch, cell);
				cell->getChain(1)->run(SH_PurposeSearch, cell);
				cell->getChain(2)->run(SH_PurposeSearch, cell);
				
				return false;
			}
			
		break; case SH_PurposeAction:
			
			if (!value) value = cell->get();
			// Unset value
			else cell->appendState(cell->getState() & ~(0x1 << value));
					
		break;
	}
	
	
	cell = cell->getCell(direction);
	
	return true;
}
